package com.guapi.gwt.reference.client;

import java.util.HashSet;
import java.util.Set;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.guapi.gwt.api.client.GuardianApiServiceAsync;
import com.guapi.gwt.api.client.SearchParameters;
import com.guapi.gwt.api.client.SearchParametersBuilder;
import com.guapi.gwt.parser.client.model.Content;
import com.guapi.gwt.parser.client.model.Search;
import com.guapi.gwt.parser.client.model.Tag;

public class SearchApp extends DockPanel {
	
	private final GuardianApiServiceAsync apiService;
	private final Set<Tag> filters = new HashSet<Tag>();
	private final Button submit =  new Button("Search");
	private FlexTable resultPanel = new FlexTable();
	private final HorizontalPanel inputPanel = new HorizontalPanel();
	private final PopupPanel pleaseWait = new PopupPanel();
	
	public SearchApp(GuardianApiServiceAsync apiServiceImpl) {
		this.apiService = apiServiceImpl;
		
		Image pleaseWaitImage = new Image("/please-wait.gif");
		
		pleaseWait.add(pleaseWaitImage);
		pleaseWait.setAnimationEnabled(true);
		
		VerticalPanel topPanel = new VerticalPanel();
		this.add(topPanel, NORTH);
		
		inputPanel.setStyleName("inputPanel");
		inputPanel.add(new Label("Enter search: "));
		final TextBox search = new TextBox();
		inputPanel.add(search);
		inputPanel.add(submit);
		topPanel.add(inputPanel);
		
		final AsyncCallback<Search> callback = new SearchCallback(this);
		
		ClickHandler submitHandler = new SubmitClickHandler(callback, search, this);
		submit.addClickHandler(submitHandler);
	}
	
	public void click() {
		submit.click();
	}
	
	private final class SubmitClickHandler implements ClickHandler {
		private final AsyncCallback<Search> callback;
		private final TextBox search;
		private final SearchApp searchApp;

		private SubmitClickHandler(AsyncCallback<Search> callback,
				TextBox search, SearchApp searchApp) {
			this.callback = callback;
			this.search = search;
			this.searchApp = searchApp;
		}

		public void onClick(ClickEvent event) {
			pleaseWait.center();
			searchApp.remove(resultPanel);
			
			SearchParameters params = new SearchParametersBuilder()
									.q(search.getText()).filters(filters).toSearchParameters();
			apiService.search(params, callback);
		}
	}

	private final class SearchCallback implements AsyncCallback<Search> {
		
		private SearchApp app;
		
		public SearchCallback(SearchApp app) {
			this.app =app;
		}

		public void onFailure(Throwable error) {
			pleaseWait.hide();
			final DialogBox errorBox = new DialogBox();
			errorBox.setModal(true);
			errorBox.setAnimationEnabled(true);
			errorBox.setText("Error");
			VerticalPanel panel = new VerticalPanel();
			panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
			panel.add(new Label(error.getMessage()));
			Button ok = new Button("Ok");
			ok.addClickHandler(new ClickHandler() {

				public void onClick(ClickEvent event) {
					errorBox.hide();
				}
		
			});
	
			panel.add(ok);
	
			errorBox.add(panel);
			errorBox.center();
		}

		public void onSuccess(Search search) {

			resultPanel = new FlexTable();
			
			VerticalPanel contentPanel = new VerticalPanel();
			for (Content content : search.getResults()) {
				FlowPanel wrapper = new FlowPanel();
				wrapper.setStyleName("separator");
				ContentSummaryDisplay contentDisplay = new ContentSummaryDisplay(content);
				wrapper.add(contentDisplay);
				contentPanel.add(wrapper);	
			}
			
			VerticalPanel filterPanel = new VerticalPanel();
			
			if (!filters.isEmpty()) {
				Label appliedFilters = new Label("Applied filters"); 
				appliedFilters.setStyleName("legend");
				filterPanel.add(appliedFilters);
				for (final Tag filter : filters) {
					
					Anchor a = new Anchor(filter.getName());
					a.setTitle("remove filter");
					
					a.addClickHandler(new ClickHandler(){
	
						public void onClick(ClickEvent event) {
							filters.remove(filter);
							submit.click();
						}});
					
					filterPanel.add(a);
				}
			}
			
			Label availableFilters = new Label("Available filters"); 
			availableFilters.setStyleName("legend");
			filterPanel.add(availableFilters);
			for (final Tag filter : search.getFilters()) {			
				if (!filters.contains(filter)) {
					Anchor a = new Anchor(filter.getName());
					a.setTitle("apply filter");
					
					a.addClickHandler(new ClickHandler(){
	
						public void onClick(ClickEvent event) {
							filters.add(filter);
							submit.click();
						}});
					
					filterPanel.add(a);
				}
			}
			resultPanel.setWidget(0, 0, contentPanel);
			resultPanel.setWidget(0, 1, filterPanel);
			resultPanel.getCellFormatter().setAlignment(0, 1, HasHorizontalAlignment.ALIGN_LEFT, HasVerticalAlignment.ALIGN_TOP);
			app.add(resultPanel, CENTER);
			pleaseWait.hide();
		}
	}
}
